home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / swtools / mipsABI / examples / sup / PORT / step07 / scmio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  18.1 KB  |  742 lines

  1. /*
  2.  * Copyright (c) 1992 Carnegie Mellon University
  3.  * All Rights Reserved.
  4.  * 
  5.  * Permission to use, copy, modify and distribute this software and its
  6.  * documentation is hereby granted, provided that both the copyright
  7.  * notice and this permission notice appear in all copies of the
  8.  * software, derivative works or modified versions, and any portions
  9.  * thereof, and that both notices appear in supporting documentation.
  10.  *
  11.  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  12.  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  13.  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  14.  *
  15.  * Carnegie Mellon requests users of this software to return to
  16.  *
  17.  *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
  18.  *  School of Computer Science
  19.  *  Carnegie Mellon University
  20.  *  Pittsburgh PA 15213-3890
  21.  *
  22.  * any improvements or extensions that they make and grant Carnegie Mellon
  23.  * the rights to redistribute these changes.
  24.  */
  25. /*
  26.  * SUP Communication Module for 4.3 BSD
  27.  *
  28.  * SUP COMMUNICATION MODULE SPECIFICATIONS:
  29.  *
  30.  * IN THIS MODULE:
  31.  *
  32.  * OUTPUT TO NETWORK
  33.  *
  34.  *   MESSAGE START/END
  35.  *    writemsg (msg)        start message
  36.  *      int msg;            message type
  37.  *    writemend ()        end message and flush data to network
  38.  *
  39.  *   MESSAGE DATA
  40.  *    writeint (i)        write int
  41.  *      int i;            integer to write
  42.  *    writestring (p)        write string
  43.  *      char *p;            string pointer
  44.  *    writefile (f)        write open file
  45.  *      int f;            open file descriptor
  46.  *
  47.  *   COMPLETE MESSAGE (start, one data block, end)
  48.  *    writemnull (msg)    write message with no data
  49.  *      int msg;            message type
  50.  *    writemint (msg,i)    write int message
  51.  *      int msg;            message type
  52.  *      int i;            integer to write
  53.  *    writemstr (msg,p)    write string message
  54.  *      int msg;            message type
  55.  *      char *p;            string pointer
  56.  *
  57.  * INPUT FROM NETWORK
  58.  *   MESSAGE START/END
  59.  *    readflush ()        flush any unread data (close)
  60.  *    readmsg (msg)        read specified message type
  61.  *      int msg;            message type
  62.  *    readmend ()        read message end
  63.  *
  64.  *   MESSAGE DATA
  65.  *    readskip ()        skip over one input data block
  66.  *    readint (i)        read int
  67.  *      int *i;            pointer to integer
  68.  *    readstring (p)        read string
  69.  *      char **p;            pointer to string pointer
  70.  *    readfile (f)        read into open file
  71.  *      int f;            open file descriptor
  72.  *
  73.  *   COMPLETE MESSAGE (start, one data block, end)
  74.  *    readmnull (msg)        read message with no data
  75.  *      int msg;            message type
  76.  *    readmint (msg,i)    read int message
  77.  *      int msg;            message type
  78.  *      int *i;            pointer to integer
  79.  *    readmstr (msg,p)    read string message
  80.  *      int msg;            message type
  81.  *      char **p;            pointer to string pointer
  82.  *
  83.  * RETURN CODES
  84.  *    All routines normally return SCMOK.  SCMERR may be returned
  85.  *    by any routine on abnormal (usually fatal) errors.  An
  86.  *    unexpected MSGGOAWAY will result in SCMEOF being returned.
  87.  *
  88.  * COMMUNICATION PROTOCOL
  89.  *    Messages always alternate, with the first message after
  90.  *    connecting being sent by the client process.
  91.  *
  92.  *    At the end of the conversation, the client process will
  93.  *    send a message to the server telling it to go away.  Then,
  94.  *    both processes will close the network connection.
  95.  *
  96.  *    Any time a process receives a message it does not expect,
  97.  *    the "readmsg" routine will send a MSGGOAWAY message and
  98.  *    return SCMEOF.
  99.  *    
  100.  *    Each message has this format:
  101.  *        ----------    ------------    ------------         ----------
  102.  *        |msg type|    |count|data|    |count|data|   ...   |ENDCOUNT|
  103.  *        ----------    ------------    ------------         ----------
  104.  *    size:  int        int  var.        int  var.             int
  105.  *
  106.  *    All ints are assumed to be 32-bit quantities.  A message
  107.  *    with no data simply has a message type followed by ENDCOUNT.
  108.  *
  109.  **********************************************************************
  110.  * HISTORY
  111.  * $Log: scmio.c,v $
  112.  * Revision 1.2  1993/05/24  17:57:26  brezak
  113.  * Remove netcrypt.c. Remove unneeded files. Cleanup make.
  114.  *
  115.  * Revision 1.1.1.1  1993/05/21  14:52:17  cgd
  116.  * initial import of CMU's SUP to NetBSD
  117.  *
  118.  * Revision 1.7  92/09/09  22:04:41  mrt
  119.  *     Removed the data encryption routines from here to netcrypt.c
  120.  *     [92/09/09            mrt]
  121.  * 
  122.  * Revision 1.6  92/08/11  12:05:57  mrt
  123.  *     Brad's changes: Delinted,Added forward declarations of 
  124.  *     static functions. Added copyright.
  125.  *     [92/07/24            mrt]
  126.  * 
  127.  * 27-Dec-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  128.  *    Added crosspatch support.
  129.  *
  130.  * 28-Jun-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  131.  *    Found error in debuging code for readint().
  132.  *
  133.  * 01-Apr-87  Glenn Marcy (gm0w) at Carnegie-Mellon University
  134.  *    Added code to readdata to "push" data back into the data buffer.
  135.  *    Added prereadcount() to return the message count size after
  136.  *    reading it and then pushing it back into the buffer.  Clear
  137.  *    any encryption when a GOAWAY message is detected before reading
  138.  *    the reason string. [V5.19]
  139.  *
  140.  * 02-Oct-86  Rudy Nedved (ern) at Carnegie-Mellon University
  141.  *    Put a timeout on reading from the network.
  142.  *
  143.  * 25-May-86  Jonathan J. Chew (jjc) at Carnegie-Mellon University
  144.  *    Renamed "howmany" parameter to routines "encode" and "decode" from
  145.  *    to "count" to avoid conflict with 4.3BSD macro.
  146.  *
  147.  * 15-Feb-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  148.  *    Added readflush() to flush any unread data from the input
  149.  *    buffer.  Called by requestend() in scm.c module.
  150.  *
  151.  * 19-Jan-86  Glenn Marcy (gm0w) at Carnegie-Mellon University
  152.  *    Added register variables to decode() for speedup.  Added I/O
  153.  *    buffering to reduce the number or read/write system calls.
  154.  *    Removed readmfil/writemfil routines which were not used and were
  155.  *    not compatable with the other similarly defined routines anyway.
  156.  *
  157.  * 19-Dec-85  Glenn Marcy (gm0w) at Carnegie-Mellon University
  158.  *    Created from scm.c I/O and crypt routines.
  159.  *
  160.  **********************************************************************
  161.  */
  162.  
  163. #include <libc.h>
  164. #include <errno.h>
  165. #include <sys/types.h>
  166. #include <sys/stat.h>
  167. #include <sys/file.h>
  168. #include <sys/time.h>
  169. #include "sup.h"
  170. #include "supmsg.h"
  171.  
  172. extern int errno;
  173.  
  174. /*************************
  175.  ***    M A C R O S    ***
  176.  *************************/
  177.  
  178. /* end of message */
  179. #define ENDCOUNT (-1)            /* end of message marker */
  180. #define NULLCOUNT (-2)            /* used for sending NULL pointer */
  181.  
  182. #define RETRIES 15            /* # of times to retry io */
  183. #define FILEXFER 2048            /* block transfer size */
  184. #define XFERSIZE(count) ((count > FILEXFER) ? FILEXFER : count)
  185.  
  186. /*********************************************
  187.  ***    G L O B A L   V A R I A B L E S    ***
  188.  *********************************************/
  189.  
  190. extern int scmerr ();            /* error printing routine */
  191. extern int netfile;            /* network file descriptor */
  192.  
  193. int scmdebug;                /* scm debug flag */
  194.  
  195. extern int cryptflag;            /* whether to encrypt/decrypt data */
  196. extern char *cryptbuf;            /* buffer for data encryption/decryption */
  197.  
  198. extern char *goawayreason;        /* reason for goaway message */
  199.  
  200. struct buf {
  201.     char b_data[FILEXFER];        /* buffered data */
  202.     char *b_ptr;            /* pointer to end of buffer */
  203.     int b_cnt;            /* number of bytes in buffer */
  204. } buffers[2];
  205. struct buf *bufptr;            /* buffer pointer */
  206.  
  207.  
  208. /***********************************************
  209.  ***    O U T P U T   T O   N E T W O R K    ***
  210.  ***********************************************/
  211.  
  212. static
  213. writedata (count,data)        /* write raw data to network */
  214. int count;
  215. char *data;
  216. {
  217.     register int x,tries;
  218.     register struct buf *bp;
  219.  
  220.     if (bufptr) {
  221.         if (bufptr->b_cnt + count <= FILEXFER) {
  222.             bcopy (data,bufptr->b_ptr,count);
  223.             bufptr->b_cnt += count;
  224.             bufptr->b_ptr += count;
  225.             return (SCMOK);
  226.         }
  227.         bp = (bufptr == buffers) ? &buffers[1] : buffers;
  228.         bcopy (data,bp->b_data,count);
  229.         bp->b_cnt = count;
  230.         bp->b_ptr = bp->b_data + count;
  231.         data = bufptr->b_data;
  232.         count = bufptr->b_cnt;
  233.         bufptr->b_cnt = 0;
  234.         bufptr->b_ptr = bufptr->b_data;
  235.         bufptr = bp;
  236.     }
  237.     tries = 0;
  238.     for (;;) {
  239.         errno = 0;
  240.         x = write (netfile,data,count);
  241.         if (x > 0)  break;
  242.         if (errno)  break;
  243.         if (++tries > RETRIES)  break;
  244.         if (scmdebug > 0)
  245.             logerr ("SCM Retrying failed network write");
  246.     }
  247.     if (x <= 0) {
  248.         if (errno == EPIPE)
  249.             return (scmerr (-1,"Network write timed out"));
  250.         if (errno)
  251.             return (scmerr (errno,"Write error on network"));
  252.         return (scmerr (-1,"Write retries failed"));
  253.     }
  254.     if (x != count)
  255.         return (scmerr (-1,"Write error on network returned %d on write of %d",x,count));
  256.     return (SCMOK);
  257. }
  258.  
  259. static
  260. writeblock (count,data)        /* write data block */
  261. int count;
  262. char *data;
  263. {
  264.     register int x;
  265.     int y = byteswap(count);
  266.  
  267.     x = writedata (sizeof(int),(char *)&y);
  268.     if (x == SCMOK)  x = writedata (count,data);
  269.     return (x);
  270. }
  271.  
  272. writemsg (msg)        /* write start of message */
  273. int msg;
  274. {
  275.     int x;
  276.  
  277.     if (scmdebug > 1)
  278.         loginfo ("SCM Writing message %d",msg);
  279.     if (bufptr)
  280.         return (scmerr (-1,"Buffering already enabled"));
  281.     bufptr = buffers;
  282.     bufptr->b_ptr = bufptr->b_data;
  283.     bufptr->b_cnt = 0;
  284.     x = byteswap (msg);
  285.     return (writedata(sizeof(int),(char *)&x));
  286. }
  287.  
  288. writemend ()        /* write end of message */
  289. {
  290.     register int count;
  291.     register char *data;
  292.     int x;
  293.  
  294.     x = byteswap (ENDCOUNT);
  295.     x = writedata (sizeof(int),(char *)&x);
  296.     if (x != SCMOK)  return (x);
  297.     if (bufptr == NULL)
  298.         return (scmerr (-1,"Buffering already disabled"));
  299.     if (bufptr->b_cnt == 0) {
  300.         bufptr = NULL;
  301.         return (SCMOK);
  302.     }
  303.     data = bufptr->b_data;
  304.     count = bufptr->b_cnt;
  305.     bufptr = NULL;
  306.     return (writedata (count, data));
  307. }
  308.  
  309. writeint (i)        /* write int as data block */
  310. int i;
  311. {
  312.     int x;
  313.     if (scmdebug > 2)
  314.         loginfo ("SCM Writing integer %d",i);
  315.     x = byteswap(i);
  316.     return (writeblock(sizeof(int),(char *)&x));
  317. }
  318.  
  319. writestring (p)        /* write string as data block */
  320. char *p;
  321. {
  322.     register int len,x;
  323.     if (p == NULL) {
  324.         int y = byteswap(NULLCOUNT);
  325.         if (scmdebug > 2)
  326.             loginfo ("SCM Writing string NULL");
  327.         return (writedata (sizeof(int),(char *)&y));
  328.     }
  329.     if (scmdebug > 2)
  330.         loginfo ("SCM Writing string %s",p);
  331.     len = strlen (p);
  332.     if (cryptflag) {
  333.         x = getcryptbuf (len+1);
  334.         if (x != SCMOK)
  335.             return (x);
  336.         encode (p,cryptbuf,len);
  337.         p = cryptbuf;
  338.     }
  339.     return (writeblock(len,p));
  340. }
  341.  
  342. writefile (f)        /* write open file as a data block */
  343. int f;
  344. {
  345.     char buf[FILEXFER];
  346.     register int number,sum,filesize,x;
  347.     int y;
  348.     struct stat statbuf;
  349.  
  350.     if (fstat(f,&statbuf) < 0)
  351.         return (scmerr (errno,"Can't access open file for message"));
  352.     filesize = statbuf.st_size;
  353.     y = byteswap(filesize);
  354.     x = writedata (sizeof(int),(char *)&y);
  355.  
  356.     if (cryptflag)  x = getcryptbuf (FILEXFER);
  357.  
  358.     if (x == SCMOK) {
  359.         sum = 0;
  360.         do {
  361.             number = read (f,buf,FILEXFER);
  362.             if (number > 0) {
  363.                 if (cryptflag) {
  364.                     encode (buf,cryptbuf,number);
  365.                     x = writedata (number,cryptbuf);
  366.                 }
  367.                 else {
  368.                     x = writedata (number,buf);
  369.                 }
  370.                 sum += number;
  371.             }
  372.         } while (x == SCMOK && number > 0);
  373.     }
  374.     if (sum != filesize)
  375.         return (scmerr (-1,"File size error on output message"));
  376.     if (number < 0)
  377.         return (scmerr (errno,"Read error on file output message"));
  378.     return (x);
  379. }
  380.  
  381. writemnull (msg)    /* write message with no data */
  382. int msg;
  383. {
  384.     register int x;
  385.     x = writemsg (msg);
  386.     if (x == SCMOK)  x = writemend ();
  387.     return (x);
  388. }
  389.  
  390. writemint (msg,i)        /* write message of one int */
  391. int msg,i;
  392. {
  393.     register int x;
  394.     x = writemsg (msg);
  395.     if (x == SCMOK)  x = writeint (i);
  396.     if (x == SCMOK)  x = writemend ();
  397.     return (x);
  398. }
  399.  
  400. writemstr (msg,p)        /* write message of one string */
  401. int msg;
  402. char *p;
  403. {
  404.     register int x;
  405.     x = writemsg (msg);
  406.     if (x == SCMOK)  x = writestring (p);
  407.     if (x == SCMOK)  x = writemend ();
  408.     return (x);
  409. }
  410.  
  411. /*************************************************
  412.  ***    I N P U T   F R O M   N E T W O R K    ***
  413.  *************************************************/
  414.  
  415. static
  416. readdata (count,data)        /* read raw data from network */
  417. int count;
  418. char *data;
  419. {
  420.     register char *p;
  421.     register int n,m,x;
  422.     int tries;
  423.     static int bufcnt = 0;
  424.     static char *bufptr;
  425.     static char buffer[FILEXFER];
  426.     static int imask;
  427.     static struct timeval timout;
  428.  
  429.     if (count < 0) {
  430.         if (bufptr + count < buffer)
  431.             return (scmerr (-1,"No space in buffer %d",count));
  432.         bufptr += count;
  433.         bufcnt -= count;
  434.         bcopy (data,bufptr,-count);
  435.         return (SCMOK);
  436.     }
  437.     if (count == 0 && data == NULL) {
  438.         bufcnt = 0;
  439.         return (SCMOK);
  440.     }
  441.     if (count <= bufcnt) {
  442.         bcopy (bufptr,data,count);
  443.         bufptr += count;
  444.         bufcnt -= count;
  445.         return (SCMOK);
  446.     }
  447.     if (bufcnt > 0) {
  448.         bcopy (bufptr,data,bufcnt);
  449.         data += bufcnt;
  450.         count -= bufcnt;
  451.     }
  452.     bufptr = buffer;
  453.     bufcnt = 0;
  454.     timout.tv_usec = 0;
  455.     timout.tv_sec = 2*60*60;
  456.     p = buffer;
  457.     n = FILEXFER;
  458.     m = count;
  459.     while (m > 0) {
  460.         tries = 0;
  461.         for (;;) {
  462.             imask = 1 << netfile;
  463.             if (select(32,(fd_set *)&imask,(fd_set *)0,(fd_set *)0,&timout) < 0)
  464.                 imask = 1;
  465.             errno = 0;
  466.             if (imask)
  467.                 x = read (netfile,p,n);
  468.             else
  469.                 return (scmerr (-1,"Timeout on network input"));
  470.             if (x > 0)  break;
  471.             if (x == 0)
  472.                 return (scmerr (-1,"Premature EOF on network input"));
  473.             if (errno)  break;
  474.             if (++tries > RETRIES)  break;
  475.             if (scmdebug > 0)
  476.                 loginfo ("SCM Retrying failed network read");
  477.         }
  478.         if (x < 0) {
  479.             if (errno)
  480.                 return (scmerr (errno,"Read error on network"));
  481.             return (scmerr (-1,"Read retries failed"));
  482.         }
  483.         p += x;
  484.         n -= x;
  485.         m -= x;
  486.         bufcnt += x;
  487.     }
  488.     bcopy (bufptr,data,count);
  489.     bufptr += count;
  490.     bufcnt -= count;
  491.     return (SCMOK);
  492. }
  493.  
  494. static
  495. int readcount (count)            /* read count of data block */
  496. int *count;
  497. {
  498.     register int x;
  499.     int y;
  500.     x = readdata (sizeof(int),(char *)&y);
  501.     if (x != SCMOK)  return (x);
  502.     *count = byteswap(y);
  503.     return (SCMOK);
  504. }
  505.  
  506. int prereadcount (count)        /* preread count of data block */
  507. int *count;
  508. {
  509.     register int x;
  510.     int y;
  511.     x = readdata (sizeof(int),(char *)&y);
  512.     if (x != SCMOK)  return (x);
  513.     x = readdata (-sizeof(int),(char *)&y);
  514.     if (x != SCMOK)  return (x);
  515.     *count = byteswap(y);
  516.     return (SCMOK);
  517. }
  518.  
  519. readflush ()
  520. {
  521.     return (readdata (0, (char *)NULL));
  522. }
  523.  
  524. readmsg (msg)        /* read header for expected message */
  525. int msg;        /* if message is unexpected, send back SCMHUH */
  526. {
  527.     register int x;
  528.     int m;
  529.     if (scmdebug > 1)
  530.         loginfo ("SCM Reading message %d",msg);
  531.     x = readdata (sizeof(int),(char *)&m);    /* msg type */
  532.     if (x != SCMOK)  return (x);
  533.     m = byteswap(m);
  534.     if (m == msg)  return (x);
  535.  
  536.     /* check for MSGGOAWAY in case he noticed problems first */
  537.     if (m != MSGGOAWAY)
  538.         return (scmerr (-1,"Received unexpected message %d",m));
  539.     (void) netcrypt ((char *)NULL);
  540.     (void) readstring (&goawayreason);
  541.     (void) readmend ();
  542.     if (goawayreason == NULL)
  543.         return (SCMEOF);
  544.     logerr ("SCM GOAWAY %s",goawayreason);
  545.     return (SCMEOF);
  546. }
  547.  
  548. readmend ()
  549. {
  550.     register int x;
  551.     int y;
  552.     x = readdata (sizeof(int),(char *)&y);
  553.     y = byteswap(y);
  554.     if (x == SCMOK && y != ENDCOUNT)
  555.         return (scmerr (-1,"Error reading end of message"));
  556.     return (x);
  557. }
  558.  
  559. readskip ()            /* skip over one input block */
  560. {
  561.     register int x;
  562.     int n;
  563.     char buf[FILEXFER];
  564.     x = readcount (&n);
  565.     if (x != SCMOK)  return (x);
  566.     if (n < 0)
  567.         return (scmerr (-1,"Invalid message count %d",n));
  568.     while (x == SCMOK && n > 0) {
  569.         x = readdata (XFERSIZE(n),buf);
  570.         n -= XFERSIZE(n);
  571.     }
  572.     return (x);
  573. }
  574.  
  575. int readint (buf)        /* read int data block */
  576. int *buf;
  577. {
  578.     register int x;
  579.     int y;
  580.     x = readcount (&y);
  581.     if (x != SCMOK)  return (x);
  582.     if (y < 0)
  583.         return (scmerr (-1,"Invalid message count %d",y));
  584.     if (y != sizeof(int))
  585.         return (scmerr (-1,"Size error for int message is %d",y));
  586.     x = readdata (sizeof(int),(char *)&y);
  587.     (*buf) = byteswap(y);
  588.     if (scmdebug > 2)
  589.         loginfo ("SCM Reading integer %d",*buf);
  590.     return (x);
  591. }
  592.  
  593. int readstring (buf)    /* read string data block */
  594. register char **buf;
  595. {
  596.     register int x;
  597.     int count;
  598.     register char *p;
  599.  
  600.     x = readcount (&count);
  601.     if (x != SCMOK)  return (x);
  602.     if (count == NULLCOUNT) {
  603.         if (scmdebug > 2)
  604.             loginfo ("SCM Reading string NULL");
  605.         *buf = NULL;
  606.         return (SCMOK);
  607.     }
  608.     if (count < 0)
  609.         return (scmerr (-1,"Invalid message count %d",count));
  610.     if (scmdebug > 3)
  611.         loginfo ("SCM Reading string count %d",count);
  612.     if ((p = (char *)malloc ((unsigned)count+1)) == NULL)
  613.         return (scmerr (-1,"Can't malloc %d bytes for string",count));
  614.     if (cryptflag) {
  615.         x = getcryptbuf (count+1);
  616.         if (x == SCMOK)  x = readdata (count,cryptbuf);
  617.         if (x != SCMOK)  return (x);
  618.     if (scmdebug > 3)
  619.         printf ("SCM Reading encrypted string %s\n",cryptbuf);
  620.         decode (cryptbuf,p,count);
  621.     }
  622.     else {
  623.         x = readdata (count,p);
  624.         if (x != SCMOK)  return (x);
  625.     }
  626.     p[count] = 0;        /* NULL at end of string */
  627.     *buf = p;
  628.     if (scmdebug > 2)
  629.         loginfo ("SCM Reading string %s",*buf);
  630.     return (SCMOK);
  631. }
  632.  
  633. readfile (f)        /* read data block into open file */
  634. int f;
  635. {
  636.     register int x;
  637.     int count;
  638.     char buf[FILEXFER];
  639.  
  640.     if (cryptflag) {
  641.         x = getcryptbuf (FILEXFER);
  642.         if (x != SCMOK)  return (x);
  643.     }
  644.     x = readcount (&count);
  645.     if (x != SCMOK)  return (x);
  646.     if (count < 0)
  647.         return (scmerr (-1,"Invalid message count %d",count));
  648.     while (x == SCMOK && count > 0) {
  649.         if (cryptflag) {
  650.             x = readdata (XFERSIZE(count),cryptbuf);
  651.             if (x == SCMOK)  decode (cryptbuf,buf,XFERSIZE(count));
  652.         }
  653.         else
  654.             x = readdata (XFERSIZE(count),buf);
  655.         if (x == SCMOK) {
  656.             (void) write (f,buf,XFERSIZE(count));
  657.             count -= XFERSIZE(count);
  658.         }
  659.     }
  660.     return (x);
  661. }
  662.  
  663. readmnull (msg)        /* read null message */
  664. int msg;
  665. {
  666.     register int x;
  667.     x = readmsg (msg);
  668.     if (x == SCMOK)  x = readmend ();
  669.     return (x);
  670. }
  671.  
  672. readmint (msg,buf)        /* read int message */
  673. int msg,*buf;
  674. {
  675.     register int x;
  676.     x = readmsg (msg);
  677.     if (x == SCMOK)  x = readint (buf);
  678.     if (x == SCMOK)  x = readmend ();
  679.     return (x);
  680. }
  681.  
  682. int readmstr (msg,buf)        /* read string message */
  683. int msg;
  684. char **buf;
  685. {
  686.     register int x;
  687.     x = readmsg (msg);
  688.     if (x == SCMOK)  x = readstring (buf);
  689.     if (x == SCMOK)  x = readmend ();
  690.     return (x);
  691. }
  692.  
  693. /**********************************
  694.  ***    C R O S S P A T C H     ***
  695.  **********************************/
  696.  
  697. crosspatch ()
  698. {
  699.     fd_set ibits, obits, xbits;
  700.     register int c;
  701.     char buf[STRINGLENGTH];
  702.  
  703.     for (;;) {
  704.         FD_ZERO (&ibits);
  705.         FD_ZERO (&obits);
  706.         FD_ZERO (&xbits);
  707.         FD_SET (0,&ibits);
  708.         FD_SET (netfile,&ibits);
  709.         if ((c = select(16, &ibits, &obits, &xbits,
  710.                 (struct timeval *)NULL)) < 1) {
  711.             if (c == -1) {
  712.                 if (errno == EINTR) {
  713.                     continue;
  714.                 }
  715.             }
  716.             sleep (5);
  717.             continue;
  718.         }
  719.         if (FD_ISSET (netfile,&ibits)) {
  720.             c = read (netfile,buf,sizeof (buf));
  721.             if (c < 0 && errno == EWOULDBLOCK)
  722.                 c = 0;
  723.             else {
  724.                 if (c <= 0) {
  725.                     break;
  726.                 }
  727.                 (void) write (1,buf,c);
  728.             }
  729.         }
  730.         if (FD_ISSET(0, &ibits)) {
  731.             c = read (0,buf,sizeof (buf));
  732.             if (c < 0 && errno == EWOULDBLOCK)
  733.                 c = 0;
  734.             else {
  735.                 if (c <= 0)
  736.                     break;
  737.                 (void) write (netfile,buf,c);
  738.             }
  739.         }
  740.     }
  741. }
  742.